// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "AbilitySystemComponent.h"
#include "AttributeSet.h"
#include "AuraAttributeSet.generated.h"

/**
 *  带返回值的单播
 */
DECLARE_DELEGATE_RetVal(FGameplayAttribute, FAttributeSignature)

// 定义了一个 属性 存取器(accessor)宏,用来调用下面四个宏,该宏会内联生成Getter和Setter方法
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
	GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
	GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
	GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
	GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)

/**
 *
 *  将GE的上下文、发起者和目标的ASC、AvatarActor、ControllerCharacter都保存了下来
 */
USTRUCT()
struct FEffectProperties
{
	GENERATED_BODY()

	FEffectProperties() = default;

	/** GE上下文 */
	FGameplayEffectContextHandle EffectContextHandle;

	/** GE施放者的ASC */
	UPROPERTY()
	UAbilitySystemComponent* SourceASC = nullptr;

	/** GE施放者的ASC的化身,实际使用ASC的对象 */
	UPROPERTY()
	AActor* SourceAvatarActor = nullptr;

	/** GE施放者的控制器 */
	UPROPERTY()
	AController* SourceController = nullptr;

	/** GE施放者的角色 */
	UPROPERTY()
	ACharacter* SourceCharacter = nullptr;

	/** GE作用目标的ASC */
	UPROPERTY()
	UAbilitySystemComponent* TargetASC = nullptr;

	/** GE作用目标的化身 */
	UPROPERTY()
	AActor* TargetAvatarActor = nullptr;

	/** GE作用目标的控制器 */
	UPROPERTY()
	AController* TargetController = nullptr;

	/** GE作用目标的角色 */
	UPROPERTY()
	ACharacter* TargetCharacter = nullptr;
};

/**
 * 属性集
 */
UCLASS()
class AURA_API UAuraAttributeSet : public UAttributeSet
{
	GENERATED_BODY()


	static void SendXPEvent(const FEffectProperties& Props);
	
	// ----------------------------------------------------------------------------------------------------------------
	//	重写相关
	// ----------------------------------------------------------------------------------------------------------------

	//指定哪些属性需要在服务器和客户端之间同步，并定义每个属性的复制条件（Replication Condition）
	virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
	
	virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
	
	virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;

public:

	UAuraAttributeSet();

	/** 标签到属性的映射 */
	TMap<FGameplayTag, FGameplayAttribute(*)()> TagsToAttributesMap;

	/** 显示浮动伤害文本 */
	static void ShowFloatingText(
		const FEffectProperties& Props, float DamageAmount, bool bIsBlockedHit, bool bIsCriticalHit
	);

	/** 存储GE修改后的回调数据 */
	static void SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props);

	// ----------------------------------------------------------------------------------------------------------------
	//	宏,生成访问器和设置器
	// ----------------------------------------------------------------------------------------------------------------
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Strength)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Intelligence)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Resilience)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Vigor)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, MaxHealth);
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, MaxMana);
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Armor)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, ArmorPenetration)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, CriticalHitChance)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, BlockChance)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, CriticalHitResistance)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, HealthRegeneration)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, ManaRegeneration)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Health);
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Mana);
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, CriticalHitDamage)
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, IncomingDamage)

	// ----------------------------------------------------------------------------------------------------------------
	//	元属性
	// ----------------------------------------------------------------------------------------------------------------

	/** 传入的伤害 */
	UPROPERTY(BlueprintReadOnly, Category="UAuraAttributeSet|Meta Attributes")
	FGameplayAttributeData IncomingDamage;

	/** 传入的经验 */
	UPROPERTY(BlueprintReadOnly, Category="UAuraAttributeSet|Meta Attributes")
	FGameplayAttributeData InComingXP;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, InComingXP)


	// ----------------------------------------------------------------------------------------------------------------
	//	主要属性
	//当前制作的RPG中，主要分为两种属性，一种是主要属性另一种次级属性。这两种类型属性的区分主要数值的计算是否需要依托于其它数值
	//举个例子，你的体力值主要在于角色的个人成长增加以及装备等的增加，它不依托于其它属性，所以是主要属性。而你的血量上限需要依托于体力数值，
	//根据体力进行一定的比例设置血量上线，它需要依托于体力属性，所以是次级属性。
	// ----------------------------------------------------------------------------------------------------------------
	
	/** 力量 */
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing= OnRep_Strength,
		Category= "Primary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData Strength;

	/** 智力 */
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing= OnRep_Intelligence,
		Category= "Primary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData Intelligence;

	/** 韧性 */
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing= OnRep_Resilience,
		Category= "Primary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData Resilience;

	/** 体力 */
	UPROPERTY(BlueprintReadOnly, ReplicatedUsing= OnRep_Vigor, Category= "Primary Attribute", meta=(AllowPrivateAccess))
	FGameplayAttributeData Vigor;


	/** 次级属性 */

	/** 血量上限，基于Vigor 体力属性计算 */
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing = OnRep_MaxHealth,
		Category="Secondary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData MaxHealth;

	/** 蓝量上限，基于Intelligence 智力属性 */
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing = OnRep_MaxMana,
		Category = "Secondary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData MaxMana;

	/** 防御 基于Resilience 韧性属性计算， 降低所受伤害*/
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing= OnRep_Armor,
		Category= "Secondary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData Armor;

	/** 护甲穿透 基于Strength 属性计算，降低敌人的防御，增加暴击率 */
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing= OnRep_ArmorPenetration,
		Category= "Secondary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData ArmorPenetration;

	/** 格挡率 基于Armor 防御属性计算，增加格挡伤害概率，触发时，降低一半所受伤害 */
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing= OnRep_BlockChance,
		Category= "Secondary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData BlockChance;

	/** 暴击几率 基于ArmorPenetration 护甲穿透属性计算，增加触发暴击伤害的概率*/
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing= OnRep_CriticalHitChance,
		Category= "Secondary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData CriticalHitChance;

	/** 暴击伤害 基于ArmorPenetration 护甲穿透属性计算，触发暴击时基于增加的伤害量 */
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing= OnRep_CriticalHitDamage,
		Category= "Secondary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData CriticalHitDamage;

	/** 暴击抵抗 基于Armor 防御属性计算，降低敌人的暴击概率 */
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing= OnRep_CriticalHitResistance,
		Category= "Secondary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData CriticalHitResistance;

	/** 血量自动恢复，基于Vigor 体力属性计算，每秒自动恢复一定血量 */
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing= OnRep_HealthRegeneration,
		Category= "Secondary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData HealthRegeneration;

	/** 蓝量自动恢复，基于Intelligence 智力属性，每秒自动恢复蓝量 */
	UPROPERTY(
		BlueprintReadOnly,
		ReplicatedUsing= OnRep_ManaRegeneration,
		Category= "Secondary Attribute",
		meta=(AllowPrivateAccess)
	)
	FGameplayAttributeData ManaRegeneration;

	// ----------------------------------------------------------------------------------------------------------------
	//	重要属性:当前血量,当前蓝量
	// ----------------------------------------------------------------------------------------------------------------

	/** 重要属性:  当前血量,当前蓝量,根据次要属性赋值*/
	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Mana, Category = "Vital Attribute", meta=(AllowPrivateAccess))
	FGameplayAttributeData Mana;

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category="Vital Attribute", meta=(AllowPrivateAccess))
	FGameplayAttributeData Health;

	// ----------------------------------------------------------------------------------------------------------------
	//	抗性
	// ----------------------------------------------------------------------------------------------------------------

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_FireResistance, Category = "Resistance Attribute")
	FGameplayAttributeData FireResistance;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, FireResistance);

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_LightningResistance, Category = "Resistance Attribute")
	FGameplayAttributeData LightningResistance;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, LightningResistance);

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_ArcaneResistance, Category = "Resistance Attribute")
	FGameplayAttributeData ArcaneResistance;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, ArcaneResistance);

	UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_PhysicalResistance, Category = "Resistance Attribute")
	FGameplayAttributeData PhysicalResistance;
	ATTRIBUTE_ACCESSORS(UAuraAttributeSet, PhysicalResistance);

private:

	// ----------------------------------------------------------------------------------------------------------------
	//	属性复制后的回调函数
	// ----------------------------------------------------------------------------------------------------------------

	UFUNCTION()
	void OnRep_Mana(const FGameplayAttributeData& OldMana) const;

	UFUNCTION()
	void OnRep_Health(const FGameplayAttributeData& OldHealth) const;

	UFUNCTION()
	void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const;

	UFUNCTION()
	void OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const;

	UFUNCTION()
	void OnRep_Strength(const FGameplayAttributeData& OldStrength) const;

	UFUNCTION()
	void OnRep_Intelligence(const FGameplayAttributeData& OldIntelligence) const;

	UFUNCTION()
	void OnRep_Resilience(const FGameplayAttributeData& OldResilience) const;

	UFUNCTION()
	void OnRep_Vigor(const FGameplayAttributeData& OldVigor) const;

	UFUNCTION()
	void OnRep_Armor(const FGameplayAttributeData& OldArmor) const;

	UFUNCTION()
	void OnRep_ArmorPenetration(const FGameplayAttributeData& OldArmorPenetration) const;

	UFUNCTION()
	void OnRep_BlockChance(const FGameplayAttributeData& OldBlockChance) const;

	UFUNCTION()
	void OnRep_CriticalHitChance(const FGameplayAttributeData& OldCriticalHitChance) const;

	UFUNCTION()
	void OnRep_CriticalHitDamage(const FGameplayAttributeData& OldCriticalHitDamage) const;

	UFUNCTION()
	void OnRep_CriticalHitResistance(const FGameplayAttributeData& OldCriticalHitResistance) const;

	UFUNCTION()
	void OnRep_HealthRegeneration(const FGameplayAttributeData& OldHealthRegeneration) const;

	UFUNCTION()
	void OnRep_ManaRegeneration(const FGameplayAttributeData& OldManaRegeneration) const;

	UFUNCTION()
	void OnRep_FireResistance(const FGameplayAttributeData& OldFireResistance) const;

	UFUNCTION()
	void OnRep_LightningResistance(const FGameplayAttributeData& OldLightningResistance) const;

	UFUNCTION()
	void OnRep_ArcaneResistance(const FGameplayAttributeData& OldArcaneResistance) const;

	UFUNCTION()
	void OnRep_PhysicalResistance(const FGameplayAttributeData& OldPhysicalResistance) const;
};
